#!/bin/bash

# 日志文件路径
LOG_FILE="/var/log/acme_cert_update.log"

# 函数：记录日志
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# 函数：错误处理
die() {
    log "错误: $1"
    exit 1
}

# 函数：获取正确的 docker compose 命令
get_compose_cmd() {
    if command -v docker-compose &>/dev/null; then
        echo "docker-compose"
    elif docker compose version &>/dev/null; then
        echo "docker compose"
    else
        die "未找到可用的 Docker Compose 命令"
    fi
}

# 函数：检测 Docker 是否安装
check_docker() {
    if ! command -v docker &> /dev/null; then
        log "Docker 未安装，请先安装 Docker 后再运行此脚本"
        log "参考安装命令:"
        log "  Ubuntu/Debian: apt-get update && apt-get install -y docker.io"
        log "  CentOS/RHEL: yum install -y docker && systemctl start docker"
        exit 1
    else
        log "Docker 已安装，版本: $(docker --version | awk '{print $3}' | tr -d ',')"
    fi
}

# 函数：检测 Docker Compose 是否安装（支持新旧版本）
check_docker_compose() {
    COMPOSE_CMD=$(get_compose_cmd)
    
    if [ "$COMPOSE_CMD" = "docker-compose" ]; then
        log "Docker Compose (v1) 已安装，版本: $(docker-compose --version | awk '{print $3}' | tr -d ',')"
    else
        log "Docker Compose (v2) 已安装，版本: $(docker compose version | awk '{print $4}')"
    fi
}

# 函数：执行 docker-compose 命令（兼容新旧版本）
docker_compose() {
    COMPOSE_CMD=$(get_compose_cmd)
    $COMPOSE_CMD "$@"
}

# 函数：删除证书
delete_certificates() {
    log "开始删除原有证书..."

    # 设置 Docker 目录为 /opt/docker
    DOCKER_DIR="/opt/docker"
    ACME_DIR="$DOCKER_DIR/acme"

    # 检查容器是否存在并删除
    if docker ps -a --format '{{.Names}}' | grep -q '^acme\.sh$'; then
        log "停止并删除 acme.sh 容器..."
        docker stop acme.sh || log "无法停止 acme.sh 容器"
        docker rm acme.sh || log "无法删除 acme.sh 容器"
    else
        log "未找到 acme.sh 容器，容器可能已删除"
    fi

    # 检查目录是否存在
    if [ -d "$ACME_DIR" ]; then
        log "删除 $ACME_DIR 目录..."
        rm -rf "$ACME_DIR" || die "无法删除 $ACME_DIR 目录"
    else
        log "目录 $ACME_DIR 不存在，无需删除"
    fi

    # 删除cron任务
    log "开始删除cron定时任务..."
    # 定义要删除的cron任务模式
    CRON_PATTERN="$ACME_DIR/upcert.sh"

    # 临时备份crontab
    CRON_BAK="/tmp/crontab_bak_$(date +%Y%m%d%H%M%S)"
    cp /etc/crontab "$CRON_BAK"
    log "已备份crontab到 $CRON_BAK"

    # 删除包含upcert.sh路径的行
    grep -v "$CRON_PATTERN" /etc/crontab > /etc/crontab.tmp && mv /etc/crontab.tmp /etc/crontab

    log "cron定时任务已删除"
    log "原有证书、容器和定时任务已删除！"
}

# 函数：创建证书
create_certificates() {
    log "开始创建证书..."

    # 检测 Docker 和 Docker Compose 是否安装
    check_docker
    check_docker_compose

    # 获取 compose 命令
    COMPOSE_CMD=$(get_compose_cmd)
    log "使用 Docker Compose 命令: $COMPOSE_CMD"

    # 设置 Docker 目录为 /opt/docker
    DOCKER_DIR="/opt/docker"
    ACME_DIR="$DOCKER_DIR/acme"

    # 创建 /opt/docker/acme 目录
    if [ ! -d "$ACME_DIR" ]; then
        log "创建目录 $ACME_DIR..."
        mkdir -p "$ACME_DIR" || die "无法创建目录 $ACME_DIR"
    else
        log "目录 $ACME_DIR 已存在"
    fi

    # 切换到 ACME 目录
    cd "$ACME_DIR" || die "无法切换到目录 $ACME_DIR"

    # 检查 .env 文件是否存在
    if [ -f .env ]; then
        log "检测到文件，将使用现有配置"
        source .env
    else
        log "未找到文件，将引导您进行配置"
        # 选择 DNS 提供商
        echo "请选择 DNS 提供商:"
        echo "1. 阿里云"
        echo "2. 腾讯云"
        echo "3. Cloudflare"
        while true; do
            read -p "输入数字 (1/2/3): " dns_provider
            case $dns_provider in
                1)
                    dns="dns_ali"
                    break
                    ;;
                2)
                    dns="dns_tencent"
                    break
                    ;;
                3)
                    dns="dns_cf"
                    break
                    ;;
                *)
                    echo "无效的选择，请输入 1、2 或 3"
                    ;;
            esac
        done

        # 输入 API 配置
        case $dns_provider in
            1)
                read -p "请输入阿里云 API Key: " api_key
                read -p "请输入阿里云 API Secret: " api_secret
                ;;
            2)
                read -p "请输入腾讯云 API SecretId: " api_key
                read -p "请输入腾讯云 API Secretkey: " api_secret
                ;;
            3)
                read -p "请输入 Cloudflare DNS全局_Token: " api_key
                read -p "请输入 Cloudflare 邮箱_mail: " api_email
                ;;
        esac

        # 输入域名和邮箱
        read -p "请输入域名，例:主域名：example.com;或泛域名：*.example.com;或二级域名：nas.example.com: " domain
        read -p "请输入邮箱（用于注册 acme.sh 账户）: " email

        # 创建 .env 文件
        log "创建文件..."
        {
            echo "DNS_PROVIDER=$dns"
            case $dns_provider in
                1)
                    echo "ALI_KEY=$api_key"
                    echo "ALI_SECRET=$api_secret"
                    ;;
                2)
                    echo "Tencent_SecretId=$api_key"
                    echo "Tencent_SecretKey=$api_secret"
                    ;;
                3)
                    echo "CF_Token=$api_key"
                    echo "CF_Email=$api_email"
            esac
            echo "DOMAIN=$domain"
            echo "EMAIL=$email"
        } > "$ACME_DIR/.env" || die "无法创建 .env 文件"
    fi

    # 创建 docker-compose.yml 文件
    log "创建 docker-compose.yml 文件..."
    cat <<EOL > "$ACME_DIR/docker-compose.yml"
version: '3'
services:
  acme.sh:
    image: neilpang/acme.sh
    container_name: acme.sh
    restart: always
    environment:
      - DNS_PROVIDER=\${DNS_PROVIDER}
      - Ali_Key=\${ALI_KEY}
      - Ali_Secret=\${ALI_SECRET}
      - Tencent_SecretId=\${Tencent_SecretId}
      - Tencent_SecretKey=\${Tencent_SecretKey}
      - CF_Token=\${CF_Token}
      - CF_Email=\${CF_Email}
    volumes:
      - $ACME_DIR:/acme.sh
    network_mode: host
    command: daemon
EOL

    # 启动 Docker 容器
    log "启动 Docker 容器..."
    $COMPOSE_CMD -f "$ACME_DIR/docker-compose.yml" down
    $COMPOSE_CMD -f "$ACME_DIR/docker-compose.yml" up -d --build || die "无法启动 Docker 容器"

    # 等待容器就绪
    log "等待容器就绪..."
    if ! docker exec "acme.sh" /bin/sh -c "echo Container is ready"; then
        sleep 5
        docker exec "acme.sh" /bin/sh -c "echo Container is ready" || die "容器未响应"
    fi

    # 清理旧证书
    log "清理旧证书..."
    rm -rf "$ACME_DIR/${DOMAIN}_ecc/"* || die "无法删除旧证书文件"
    echo "updatecert" > "$ACME_DIR/updatecert.txt" || die "无法创建标志文件"
    rm -rf $ACME_DIR/docker-compose.yml

    # 注册 acme.sh 账户
    log "注册 acme.sh 账户..."
    docker exec acme.sh acme.sh --register-account -m "$EMAIL" 
    sleep 5
    docker exec acme.sh acme.sh --register-account -m "$EMAIL" || die "注册账户失败,请再次运行程序"

    # 生成 SSL 证书
    log "生成 SSL 证书..."
    docker exec "acme.sh" /bin/sh -c "cd /root/.acme.sh && ./acme.sh --issue --dns ${DNS_PROVIDER} -d ${DOMAIN}" || die "证书生成失败,请再次运行程序"

    # 检测证书是否生成成功
    CERT_DIR="$ACME_DIR/${DOMAIN}_ecc"
    if [ -f "$CERT_DIR/ca.cer" ]; then
        log "SSL 证书已生成，路径为: $CERT_DIR"
        
        # 创建证书存放目录
        CERT_STORE_DIR="/etc/ssl/$DOMAIN"
        log "创建证书存放目录: $CERT_STORE_DIR"
        mkdir -p "$CERT_STORE_DIR" || die "无法创建证书存放目录"
        
        # 复制证书文件
        log "复制证书文件到 $CERT_STORE_DIR..."
        cp -f "$CERT_DIR/fullchain.cer" "$CERT_STORE_DIR/cert.pem"
        cp -f "$CERT_DIR/$DOMAIN.key" "$CERT_STORE_DIR/privkey.pem"
        cp -f "$CERT_DIR/fullchain.cer" "$CERT_STORE_DIR/fullchain.pem"
        cp -f "$CERT_DIR/ca.cer" "$CERT_STORE_DIR/chain.pem"
        
        # 设置权限
        chmod 600 "$CERT_STORE_DIR/privkey.pem"
        chmod 644 "$CERT_STORE_DIR/cert.pem"
        chmod 644 "$CERT_STORE_DIR/fullchain.pem"
        chmod 644 "$CERT_STORE_DIR/chain.pem"
        
        # 生成定时更新证书的脚本
        log "生成定时更新证书的脚本..."
        cat <<EOL > "$ACME_DIR/upcert.sh"
#!/bin/bash
# 获取 compose 命令
if command -v docker-compose &>/dev/null; then
    COMPOSE_CMD="docker-compose"
elif docker compose version &>/dev/null; then
    COMPOSE_CMD="docker compose"
else
    echo "错误: 未找到 Docker Compose"
    exit 1
fi

# 清理旧证书
rm -rf "$ACME_DIR/${DOMAIN}_ecc/"* || echo "警告: 无法删除旧证书文件"
echo "updatecert" > "$ACME_DIR/updatecert.txt" || echo "警告: 无法创建标志文件"
\$COMPOSE_CMD -f "$ACME_DIR/docker-compose.yml" down
\$COMPOSE_CMD -f "$ACME_DIR/docker-compose.yml" up -d

# 等待容器就绪
if ! docker exec "acme.sh" /bin/sh -c "echo Container is ready"; then
    sleep 5
    docker exec "acme.sh" /bin/sh -c "echo Container is ready" || echo "容器未响应"
fi
docker exec acme.sh acme.sh --register-account -m "$EMAIL" 
sleep 5
docker exec acme.sh acme.sh --register-account -m "$EMAIL" || echo "注册账户失败"
# 生成 SSL 证书
docker exec "acme.sh" /bin/sh -c "cd /root/.acme.sh && ./acme.sh --issue --dns ${DNS_PROVIDER} -d ${DOMAIN}"
# 检测证书是否生成成功
CERT_DIR="$ACME_DIR/${DOMAIN}_ecc"
if [ -f "$CERT_DIR/ca.cer" ]; then
    echo "SSL 证书已生成，路径为: $CERT_DIR"
    echo "替换证书中..."
    # 复制证书文件
    cp -f "$CERT_DIR/fullchain.cer" "$CERT_STORE_DIR/cert.pem"
    cp -f "$CERT_DIR/$DOMAIN.key" "$CERT_STORE_DIR/privkey.pem"
    cp -f "$CERT_DIR/fullchain.cer" "$CERT_STORE_DIR/fullchain.pem"
    cp -f "$CERT_DIR/ca.cer" "$CERT_STORE_DIR/chain.pem"
    # 设置权限
    chmod 600 "$CERT_STORE_DIR/privkey.pem"
    chmod 644 "$CERT_STORE_DIR/cert.pem"
    chmod 644 "$CERT_STORE_DIR/fullchain.pem"
    chmod 644 "$CERT_STORE_DIR/chain.pem"
    echo "证书更新完成"
    # 重启相关服务
    systemctl restart nginx || true
    systemctl restart apache2 || true
else
    echo "错误: 未找到证书文件 ca.cer，证书生成失败"
    exit 1
fi
EOL
        chmod +x "$ACME_DIR/upcert.sh"
        log "定时更新脚本已生成：$ACME_DIR/upcert.sh"

        # 定义两条 Cron 任务
        CRON_JOB_1="15 0 5 * * root $ACME_DIR/upcert.sh"  # 5号 0:15
        CRON_JOB_2="15 12 20 * * root $ACME_DIR/upcert.sh" # 20号 12:15

        # 检查并添加第一条任务
        if ! grep -Fxq "$CRON_JOB_1" /etc/crontab; then
            log "将定时任务每月（5号 0:15）更新证书..."
            echo "$CRON_JOB_1" >> /etc/crontab || die "无法写入 /etc/crontab"
        else
            log "定时更新证书任务（5号 0:15）已存在，无需重复添加"
        fi

        # 检查并添加第二条任务
        if ! grep -Fxq "$CRON_JOB_2" /etc/crontab; then
            log "将定时任务每月（20号 12:15）更新证书..."
            echo "$CRON_JOB_2" >> /etc/crontab || die "无法写入 /etc/crontab"
        else
            log "定时更新证书任务（20号 12:15）已存在，无需重复添加"
        fi
    else
        die "未找到证书文件 ca.cer，证书生成失败，请检查日志"
    fi
}

# 主菜单选项
log "请选择操作："
echo "1. 创建证书"
echo "2. 删除原有证书"
echo "20 秒内未选择，将自动选择创建证书..."

# 设置 20 秒超时
read -t 20 -p "请输入数字 (1/2): " choice

# 默认选择创建证书
if [ -z "$choice" ]; then
    choice=1
    log "20 秒内未选择，默认选择创建证书"
fi

# 根据选择执行操作
case $choice in
    1)
        log "用户选择创建证书"
        create_certificates
        ;;
    2)
        log "用户选择删除原有证书"
        delete_certificates
        ;;
    *)
        log "无效的选择，请输入 1 或 2"
        exit 1
        ;;
esac

log "脚本执行完成！"